home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the 3D Game Programming Gurus / gurus.iso / DirectX / dx9sdkcp.exe / SDK (C++) / Bin / DXUtils / Visual Studio 6.0 Wizards / Source Code / Template / d3dapp.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-12  |  59.9 KB  |  1,623 lines

  1. //-----------------------------------------------------------------------------
  2. // File: D3DApp.cpp
  3. //
  4. // Desc: Application class for the Direct3D samples framework library.
  5. //-----------------------------------------------------------------------------
  6. #define STRICT
  7. $$IF(DLG)
  8. #include "stdafx.h"
  9. $$ENDIF
  10. #include <windows.h>
  11. #include <windowsx.h>
  12. #include <mmsystem.h>
  13. #include <stdio.h>
  14. #include <tchar.h>
  15. #include <D3D9.h>
  16. #include "DXUtil.h"
  17. #include "D3DUtil.h"
  18. #include "D3DEnumeration.h"
  19. #include "D3DSettings.h"
  20. #include "D3DApp.h"
  21. #include "resource.h"
  22.  
  23.  
  24.  
  25.  
  26. //-----------------------------------------------------------------------------
  27. // Global access to the app (needed for the global WndProc())
  28. //-----------------------------------------------------------------------------
  29. static CD3DApplication* g_pD3DApp = NULL;
  30.  
  31.  
  32.  
  33.  
  34. //-----------------------------------------------------------------------------
  35. // Name: CD3DApplication()
  36. // Desc: Constructor
  37. //-----------------------------------------------------------------------------
  38. CD3DApplication::CD3DApplication()
  39. {
  40.     g_pD3DApp           = this;
  41.  
  42.     m_pD3D              = NULL;
  43.     m_pd3dDevice        = NULL;
  44.     m_hWnd              = NULL;
  45.     m_hWndFocus         = NULL;
  46.     m_hMenu             = NULL;
  47.     m_bWindowed         = true;
  48.     m_bActive           = false;
  49.     m_bDeviceLost       = false;
  50.     m_bMinimized        = false;
  51.     m_bMaximized        = false;
  52.     m_bIgnoreSizeChange = false;
  53.     m_bDeviceObjectsInited = false;
  54.     m_bDeviceObjectsRestored = false;
  55.     m_dwCreateFlags     = 0;
  56.  
  57.     m_bFrameMoving      = true;
  58.     m_bSingleStep       = false;
  59.     m_fTime             = 0.0f;
  60.     m_fElapsedTime      = 0.0f;
  61.     m_fFPS              = 0.0f;
  62.     m_strDeviceStats[0] = _T('\0');
  63.     m_strFrameStats[0]  = _T('\0');
  64.  
  65.     m_strWindowTitle    = _T("D3D9 Application");
  66.     m_dwCreationWidth   = 400;
  67.     m_dwCreationHeight  = 300;
  68.     m_bShowCursorWhenFullscreen = false;
  69.     m_bStartFullscreen  = false;
  70.  
  71.     Pause( true ); // Pause until we're ready to render
  72.  
  73.     // When m_bClipCursorWhenFullscreen is true, the cursor is limited to
  74.     // the device window when the app goes fullscreen.  This prevents users
  75.     // from accidentally clicking outside the app window on a multimon system.
  76.     // This flag is turned off by default for debug builds, since it makes 
  77.     // multimon debugging difficult.
  78. #if defined(_DEBUG) || defined(DEBUG)
  79.     m_bClipCursorWhenFullscreen = false;
  80. #else
  81.     m_bClipCursorWhenFullscreen = true;
  82. #endif
  83. }
  84.  
  85.  
  86.  
  87.  
  88. //-----------------------------------------------------------------------------
  89. // Name: WndProc()
  90. // Desc: Static msg handler which passes messages to the application class.
  91. //-----------------------------------------------------------------------------
  92. LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  93. {
  94.     return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
  95. }
  96.  
  97.  
  98.  
  99. //-----------------------------------------------------------------------------
  100. // Name: ConfirmDeviceHelper()
  101. // Desc: Static function used by D3DEnumeration
  102. //-----------------------------------------------------------------------------
  103. bool CD3DApplication::ConfirmDeviceHelper( D3DCAPS9* pCaps, VertexProcessingType vertexProcessingType, 
  104.                          D3DFORMAT backBufferFormat )
  105. {
  106.     DWORD dwBehavior;
  107.  
  108.     if (vertexProcessingType == SOFTWARE_VP)
  109.         dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  110.     else if (vertexProcessingType == MIXED_VP)
  111.         dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
  112.     else if (vertexProcessingType == HARDWARE_VP)
  113.         dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  114.     else if (vertexProcessingType == PURE_HARDWARE_VP)
  115.         dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
  116.     else
  117.         dwBehavior = 0; // TODO: throw exception
  118.     
  119.     return SUCCEEDED( g_pD3DApp->ConfirmDevice( pCaps, dwBehavior, backBufferFormat ) );
  120. }
  121.  
  122.  
  123.  
  124.  
  125. //-----------------------------------------------------------------------------
  126. // Name: Create()
  127. // Desc:
  128. //-----------------------------------------------------------------------------
  129. HRESULT CD3DApplication::Create( HINSTANCE hInstance )
  130. {
  131.     HRESULT hr;
  132.  
  133.     // Create the Direct3D object
  134.     m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
  135.     if( m_pD3D == NULL )
  136.         return DisplayErrorMsg( D3DAPPERR_NODIRECT3D, MSGERR_APPMUSTEXIT );
  137.  
  138.     // Build a list of Direct3D adapters, modes and devices. The
  139.     // ConfirmDevice() callback is used to confirm that only devices that
  140.     // meet the app's requirements are considered.
  141.     m_d3dEnumeration.SetD3D( m_pD3D );
  142.     m_d3dEnumeration.ConfirmDeviceCallback = ConfirmDeviceHelper;
  143.     if( FAILED( hr = m_d3dEnumeration.Enumerate() ) )
  144.     {
  145.         SAFE_RELEASE( m_pD3D );
  146.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  147.     }
  148.  
  149.     // Unless a substitute hWnd has been specified, create a window to
  150.     // render into
  151.     if( m_hWnd == NULL)
  152.     {
  153.         // Register the windows class
  154.         WNDCLASS wndClass = { 0, WndProc, 0, 0, hInstance,
  155.                               LoadIcon( hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
  156.                               LoadCursor( NULL, IDC_ARROW ),
  157.                               (HBRUSH)GetStockObject(WHITE_BRUSH),
  158.                               NULL, _T("D3D Window") };
  159.         RegisterClass( &wndClass );
  160.  
  161.         // Set the window's initial style
  162.         m_dwWindowStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | 
  163.                           WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE;
  164.  
  165.         // Set the window's initial width
  166.         RECT rc;
  167.         SetRect( &rc, 0, 0, m_dwCreationWidth, m_dwCreationHeight );
  168.         AdjustWindowRect( &rc, m_dwWindowStyle, true );
  169.  
  170.         // Create the render window
  171.         m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle, m_dwWindowStyle,
  172.                                CW_USEDEFAULT, CW_USEDEFAULT,
  173.                                (rc.right-rc.left), (rc.bottom-rc.top), 0,
  174.                                LoadMenu( hInstance, MAKEINTRESOURCE(IDR_MENU) ),
  175.                                hInstance, 0 );
  176.     }
  177.  
  178.     // The focus window can be a specified to be a different window than the
  179.     // device window.  If not, use the device window as the focus window.
  180.     if( m_hWndFocus == NULL )
  181.         m_hWndFocus = m_hWnd;
  182.  
  183.     // Save window properties
  184.     m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  185.     GetWindowRect( m_hWnd, &m_rcWindowBounds );
  186.     GetClientRect( m_hWnd, &m_rcWindowClient );
  187.  
  188.     if( FAILED( hr = ChooseInitialD3DSettings() ) )
  189.     {
  190.         SAFE_RELEASE( m_pD3D );
  191.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  192.     }
  193.  
  194.     // Initialize the application timer
  195.     DXUtil_Timer( TIMER_START );
  196.  
  197.     // Initialize the app's custom scene stuff
  198.     if( FAILED( hr = OneTimeSceneInit() ) )
  199.     {
  200.         SAFE_RELEASE( m_pD3D );
  201.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  202.     }
  203.  
  204.     // Initialize the 3D environment for the app
  205.     if( FAILED( hr = Initialize3DEnvironment() ) )
  206.     {
  207.         SAFE_RELEASE( m_pD3D );
  208.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  209.     }
  210.  
  211.     // The app is ready to go
  212.     Pause( false );
  213.  
  214.     return S_OK;
  215. }
  216.  
  217.  
  218.  
  219.  
  220. //-----------------------------------------------------------------------------
  221. // Name: FindBestWindowedMode()
  222. // Desc: Sets up m_d3dSettings with best available windowed mode, subject to 
  223. //       the bRequireHAL and bRequireREF constraints.  Returns false if no such
  224. //       mode can be found.
  225. //-----------------------------------------------------------------------------
  226. bool CD3DApplication::FindBestWindowedMode( bool bRequireHAL, bool bRequireREF )
  227. {
  228.     // Get display mode of primary adapter (which is assumed to be where the window 
  229.     // will appear)
  230.     D3DDISPLAYMODE primaryDesktopDisplayMode;
  231.     m_pD3D->GetAdapterDisplayMode(0, &primaryDesktopDisplayMode);
  232.  
  233.     D3DAdapterInfo* pBestAdapterInfo = NULL;
  234.     D3DDeviceInfo* pBestDeviceInfo = NULL;
  235.     D3DDeviceCombo* pBestDeviceCombo = NULL;
  236.  
  237.     for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
  238.     {
  239.         D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
  240.         for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
  241.         {
  242.             D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
  243.             if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
  244.                 continue;
  245.             if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
  246.                 continue;
  247.             for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
  248.             {
  249.                 D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
  250.                 bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
  251.                 if (!pDeviceCombo->IsWindowed)
  252.                     continue;
  253.                 if (pDeviceCombo->AdapterFormat != primaryDesktopDisplayMode.Format)
  254.                     continue;
  255.                 // If we haven't found a compatible DeviceCombo yet, or if this set
  256.                 // is better (because it's a HAL, and/or because formats match better),
  257.                 // save it
  258.                 if( pBestDeviceCombo == NULL || 
  259.                     pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceCombo->DevType == D3DDEVTYPE_HAL ||
  260.                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
  261.                 {
  262.                     pBestAdapterInfo = pAdapterInfo;
  263.                     pBestDeviceInfo = pDeviceInfo;
  264.                     pBestDeviceCombo = pDeviceCombo;
  265.                     if( pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesBB )
  266.                     {
  267.                         // This windowed device combo looks great -- take it
  268.                         goto EndWindowedDeviceComboSearch;
  269.                     }
  270.                     // Otherwise keep looking for a better windowed device combo
  271.                 }
  272.             }
  273.         }
  274.     }
  275. EndWindowedDeviceComboSearch:
  276.     if (pBestDeviceCombo == NULL )
  277.         return false;
  278.  
  279.     m_d3dSettings.pWindowed_AdapterInfo = pBestAdapterInfo;
  280.     m_d3dSettings.pWindowed_DeviceInfo = pBestDeviceInfo;
  281.     m_d3dSettings.pWindowed_DeviceCombo = pBestDeviceCombo;
  282.     m_d3dSettings.IsWindowed = true;
  283.     m_d3dSettings.Windowed_DisplayMode = primaryDesktopDisplayMode;
  284.     m_d3dSettings.Windowed_Width = m_rcWindowClient.right - m_rcWindowClient.left;
  285.     m_d3dSettings.Windowed_Height = m_rcWindowClient.bottom - m_rcWindowClient.top;
  286.     if (m_d3dEnumeration.AppUsesDepthBuffer)
  287.         m_d3dSettings.Windowed_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
  288.     m_d3dSettings.Windowed_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
  289.     m_d3dSettings.Windowed_MultisampleQuality = 0;
  290.     m_d3dSettings.Windowed_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
  291.     m_d3dSettings.Windowed_PresentInterval = *(UINT*)pBestDeviceCombo->pPresentIntervalList->GetPtr(0);
  292.     return true;
  293. }
  294.  
  295.  
  296.  
  297.  
  298. //-----------------------------------------------------------------------------
  299. // Name: FindBestFullscreenMode()
  300. // Desc: Sets up m_d3dSettings with best available fullscreen mode, subject to 
  301. //       the bRequireHAL and bRequireREF constraints.  Returns false if no such
  302. //       mode can be found.
  303. //-----------------------------------------------------------------------------
  304. bool CD3DApplication::FindBestFullscreenMode( bool bRequireHAL, bool bRequireREF )
  305. {
  306.     // For fullscreen, default to first HAL DeviceCombo that supports the current desktop 
  307.     // display mode, or any display mode if HAL is not compatible with the desktop mode, or 
  308.     // non-HAL if no HAL is available
  309.     D3DDISPLAYMODE adapterDesktopDisplayMode;
  310.     D3DDISPLAYMODE bestAdapterDesktopDisplayMode;
  311.     D3DDISPLAYMODE bestDisplayMode;
  312.     bestAdapterDesktopDisplayMode.Width = 0;
  313.     bestAdapterDesktopDisplayMode.Height = 0;
  314.     bestAdapterDesktopDisplayMode.Format = D3DFMT_UNKNOWN;
  315.     bestAdapterDesktopDisplayMode.RefreshRate = 0;
  316.  
  317.     D3DAdapterInfo* pBestAdapterInfo = NULL;
  318.     D3DDeviceInfo* pBestDeviceInfo = NULL;
  319.     D3DDeviceCombo* pBestDeviceCombo = NULL;
  320.  
  321.     for( UINT iai = 0; iai < m_d3dEnumeration.m_pAdapterInfoList->Count(); iai++ )
  322.     {
  323.         D3DAdapterInfo* pAdapterInfo = (D3DAdapterInfo*)m_d3dEnumeration.m_pAdapterInfoList->GetPtr(iai);
  324.         m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &adapterDesktopDisplayMode );
  325.         for( UINT idi = 0; idi < pAdapterInfo->pDeviceInfoList->Count(); idi++ )
  326.         {
  327.             D3DDeviceInfo* pDeviceInfo = (D3DDeviceInfo*)pAdapterInfo->pDeviceInfoList->GetPtr(idi);
  328.             if (bRequireHAL && pDeviceInfo->DevType != D3DDEVTYPE_HAL)
  329.                 continue;
  330.             if (bRequireREF && pDeviceInfo->DevType != D3DDEVTYPE_REF)
  331.                 continue;
  332.             for( UINT idc = 0; idc < pDeviceInfo->pDeviceComboList->Count(); idc++ )
  333.             {
  334.                 D3DDeviceCombo* pDeviceCombo = (D3DDeviceCombo*)pDeviceInfo->pDeviceComboList->GetPtr(idc);
  335.                 bool bAdapterMatchesBB = (pDeviceCombo->BackBufferFormat == pDeviceCombo->AdapterFormat);
  336.                 bool bAdapterMatchesDesktop = (pDeviceCombo->AdapterFormat == adapterDesktopDisplayMode.Format);
  337.                 if (pDeviceCombo->IsWindowed)
  338.                     continue;
  339.                 // If we haven't found a compatible set yet, or if this set
  340.                 // is better (because it's a HAL, and/or because formats match better),
  341.                 // save it
  342.                 if (pBestDeviceCombo == NULL ||
  343.                     pBestDeviceCombo->DevType != D3DDEVTYPE_HAL && pDeviceInfo->DevType == D3DDEVTYPE_HAL ||
  344.                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && pBestDeviceCombo->AdapterFormat != adapterDesktopDisplayMode.Format && bAdapterMatchesDesktop ||
  345.                     pDeviceCombo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB )
  346.                 {
  347.                     bestAdapterDesktopDisplayMode = adapterDesktopDisplayMode;
  348.                     pBestAdapterInfo = pAdapterInfo;
  349.                     pBestDeviceInfo = pDeviceInfo;
  350.                     pBestDeviceCombo = pDeviceCombo;
  351.                     if (pDeviceInfo->DevType == D3DDEVTYPE_HAL && bAdapterMatchesDesktop && bAdapterMatchesBB)
  352.                     {
  353.                         // This fullscreen device combo looks great -- take it
  354.                         goto EndFullscreenDeviceComboSearch;
  355.                     }
  356.                     // Otherwise keep looking for a better fullscreen device combo
  357.                 }
  358.             }
  359.         }
  360.     }
  361. EndFullscreenDeviceComboSearch:
  362.     if (pBestDeviceCombo == NULL)
  363.         return false;
  364.  
  365.     // Need to find a display mode on the best adapter that uses pBestDeviceCombo->AdapterFormat
  366.     // and is as close to bestAdapterDesktopDisplayMode's res as possible
  367.     bestDisplayMode.Width = 0;
  368.     bestDisplayMode.Height = 0;
  369.     bestDisplayMode.Format = D3DFMT_UNKNOWN;
  370.     bestDisplayMode.RefreshRate = 0;
  371.     for( UINT idm = 0; idm < pBestAdapterInfo->pDisplayModeList->Count(); idm++ )
  372.     {
  373.         D3DDISPLAYMODE* pdm = (D3DDISPLAYMODE*)pBestAdapterInfo->pDisplayModeList->GetPtr(idm);
  374.         if( pdm->Format != pBestDeviceCombo->AdapterFormat )
  375.             continue;
  376.         if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
  377.             pdm->Height == bestAdapterDesktopDisplayMode.Height && 
  378.             pdm->RefreshRate == bestAdapterDesktopDisplayMode.RefreshRate )
  379.         {
  380.             // found a perfect match, so stop
  381.             bestDisplayMode = *pdm;
  382.             break;
  383.         }
  384.         else if( pdm->Width == bestAdapterDesktopDisplayMode.Width &&
  385.                  pdm->Height == bestAdapterDesktopDisplayMode.Height && 
  386.                  pdm->RefreshRate > bestDisplayMode.RefreshRate )
  387.         {
  388.             // refresh rate doesn't match, but width/height match, so keep this
  389.             // and keep looking
  390.             bestDisplayMode = *pdm;
  391.         }
  392.         else if( pdm->Width == bestAdapterDesktopDisplayMode.Width )
  393.         {
  394.             // width matches, so keep this and keep looking
  395.             bestDisplayMode = *pdm;
  396.         }
  397.         else if( bestDisplayMode.Width == 0 )
  398.         {
  399.             // we don't have anything better yet, so keep this and keep looking
  400.             bestDisplayMode = *pdm;
  401.         }
  402.     }
  403.  
  404.     m_d3dSettings.pFullscreen_AdapterInfo = pBestAdapterInfo;
  405.     m_d3dSettings.pFullscreen_DeviceInfo = pBestDeviceInfo;
  406.     m_d3dSettings.pFullscreen_DeviceCombo = pBestDeviceCombo;
  407.     m_d3dSettings.IsWindowed = false;
  408.     m_d3dSettings.Fullscreen_DisplayMode = bestDisplayMode;
  409.     if (m_d3dEnumeration.AppUsesDepthBuffer)
  410.         m_d3dSettings.Fullscreen_DepthStencilBufferFormat = *(D3DFORMAT*)pBestDeviceCombo->pDepthStencilFormatList->GetPtr(0);
  411.     m_d3dSettings.Fullscreen_MultisampleType = *(D3DMULTISAMPLE_TYPE*)pBestDeviceCombo->pMultiSampleTypeList->GetPtr(0);
  412.     m_d3dSettings.Fullscreen_MultisampleQuality = 0;
  413.     m_d3dSettings.Fullscreen_VertexProcessingType = *(VertexProcessingType*)pBestDeviceCombo->pVertexProcessingTypeList->GetPtr(0);
  414.     m_d3dSettings.Fullscreen_PresentInterval = D3DPRESENT_INTERVAL_DEFAULT;
  415.     return true;
  416. }
  417.  
  418.  
  419.  
  420.  
  421. //-----------------------------------------------------------------------------
  422. // Name: ChooseInitialD3DSettings()
  423. // Desc: 
  424. //-----------------------------------------------------------------------------
  425. HRESULT CD3DApplication::ChooseInitialD3DSettings()
  426. {
  427.     bool bFoundFullscreen = FindBestFullscreenMode( false, false );
  428.     bool bFoundWindowed = FindBestWindowedMode( false, false );
  429.  
  430.     if( m_bStartFullscreen && bFoundFullscreen )
  431.         m_d3dSettings.IsWindowed = false;
  432.     if( !bFoundWindowed && bFoundFullscreen )
  433.         m_d3dSettings.IsWindowed = false;
  434.  
  435.     if( !bFoundFullscreen && !bFoundWindowed )
  436.         return D3DAPPERR_NOCOMPATIBLEDEVICES;
  437.  
  438.     return S_OK;
  439. }
  440.  
  441.  
  442.  
  443.  
  444. //-----------------------------------------------------------------------------
  445. // Name: MsgProc()
  446. // Desc: Message handling function.
  447. //-----------------------------------------------------------------------------
  448. LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
  449.                                   LPARAM lParam )
  450. {
  451.     switch( uMsg )
  452.     {
  453.         case WM_PAINT:
  454.             // Handle paint messages when the app is paused
  455.             if( m_pd3dDevice && !m_bActive && m_bWindowed &&
  456.                 m_bDeviceObjectsInited && m_bDeviceObjectsRestored )
  457.             {
  458.                 Render();
  459.                 m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  460.             }
  461.             break;
  462.  
  463.         case WM_GETMINMAXINFO:
  464.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
  465.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
  466.             break;
  467.  
  468.         case WM_ENTERSIZEMOVE:
  469.             // Halt frame movement while the app is sizing or moving
  470.             Pause( true );
  471.             break;
  472.  
  473.         case WM_SIZE:
  474.             // Pick up possible changes to window style due to maximize, etc.
  475.             if( m_bWindowed && m_hWnd != NULL )
  476.                 m_dwWindowStyle = GetWindowLong( m_hWnd, GWL_STYLE );
  477.  
  478.             if( SIZE_MINIMIZED == wParam )
  479.             {
  480.                 if( m_bClipCursorWhenFullscreen && !m_bWindowed )
  481.                     ClipCursor( NULL );
  482.                 Pause( true ); // Pause while we're minimized
  483.                 m_bMinimized = true;
  484.                 m_bMaximized = false;
  485.             }
  486.             else if( SIZE_MAXIMIZED == wParam )
  487.             {
  488.                 if( m_bMinimized )
  489.                     Pause( false ); // Unpause since we're no longer minimized
  490.                 m_bMinimized = false;
  491.                 m_bMaximized = true;
  492.                 HandlePossibleSizeChange();
  493.             }
  494.             else if( SIZE_RESTORED == wParam )
  495.             {
  496.                 if( m_bMaximized )
  497.                 {
  498.                     m_bMaximized = false;
  499.                     HandlePossibleSizeChange();
  500.                 }
  501.                 else if( m_bMinimized)
  502.                 {
  503.                     Pause( false ); // Unpause since we're no longer minimized
  504.                     m_bMinimized = false;
  505.                     HandlePossibleSizeChange();
  506.                 }
  507.                 else
  508.                 {
  509.                     // If we're neither maximized nor minimized, the window size 
  510.                     // is changing by the user dragging the window edges.  In this 
  511.                     // case, we don't reset the device yet -- we wait until the 
  512.                     // user stops dragging, and a WM_EXITSIZEMOVE message comes.
  513.                 }
  514.             }
  515.             break;
  516.  
  517.         case WM_EXITSIZEMOVE:
  518.             Pause( false );
  519.             HandlePossibleSizeChange();
  520.             break;
  521.  
  522.         case WM_SETCURSOR:
  523.             // Turn off Windows cursor in fullscreen mode
  524.             if( m_bActive && !m_bWindowed )
  525.             {
  526.                 SetCursor( NULL );
  527.                 if( m_bShowCursorWhenFullscreen )
  528.                     m_pd3dDevice->ShowCursor( true );
  529.                 return true; // prevent Windows from setting cursor to window class cursor
  530.             }
  531.             break;
  532.  
  533.          case WM_MOUSEMOVE:
  534.             if( m_bActive && m_pd3dDevice != NULL )
  535.             {
  536.                 POINT ptCursor;
  537.                 GetCursorPos( &ptCursor );
  538.                 if( !m_bWindowed )
  539.                     ScreenToClient( m_hWnd, &ptCursor );
  540.                 m_pd3dDevice->SetCursorPosition( ptCursor.x, ptCursor.y, 0 );
  541.             }
  542.             break;
  543.  
  544.        case WM_ENTERMENULOOP:
  545.             // Pause the app when menus are displayed
  546.             Pause(true);
  547.             break;
  548.  
  549.         case WM_EXITMENULOOP:
  550.             Pause(false);
  551.             break;
  552.  
  553.         case WM_NCHITTEST:
  554.             // Prevent the user from selecting the menu in fullscreen mode
  555.             if( !m_bWindowed )
  556.                 return HTCLIENT;
  557.             break;
  558.  
  559.         case WM_POWERBROADCAST:
  560.             switch( wParam )
  561.             {
  562.                 #ifndef PBT_APMQUERYSUSPEND
  563.                     #define PBT_APMQUERYSUSPEND 0x0000
  564.                 #endif
  565.                 case PBT_APMQUERYSUSPEND:
  566.                     // At this point, the app should save any data for open
  567.                     // network connections, files, etc., and prepare to go into
  568.                     // a suspended mode.
  569.                     return true;
  570.  
  571.                 #ifndef PBT_APMRESUMESUSPEND
  572.                     #define PBT_APMRESUMESUSPEND 0x0007
  573.                 #endif
  574.                 case PBT_APMRESUMESUSPEND:
  575.                     // At this point, the app should recover any data, network
  576.                     // connections, files, etc., and resume running from when
  577.                     // the app was suspended.
  578.                     return true;
  579.             }
  580.             break;
  581.  
  582.         case WM_SYSCOMMAND:
  583.             // Prevent moving/sizing and power loss in fullscreen mode
  584.             switch( wParam )
  585.             {
  586.                 case SC_MOVE:
  587.                 case SC_SIZE:
  588.                 case SC_MAXIMIZE:
  589.                 case SC_KEYMENU:
  590.                 case SC_MONITORPOWER:
  591.                     if( false == m_bWindowed )
  592.                         return 1;
  593.                     break;
  594.             }
  595.             break;
  596.  
  597.         case WM_COMMAND:
  598.             switch( LOWORD(wParam) )
  599.             {
  600.                 case IDM_CHANGEDEVICE:
  601.                     // Prompt the user to select a new device or mode
  602.                     Pause(true);
  603.                     UserSelectNewDevice();
  604.                     Pause(false);
  605.                     return 0;
  606.  
  607.                 case IDM_TOGGLEFULLSCREEN:
  608.                     // Toggle the fullscreen/window mode
  609.                     Pause( true );
  610.                     if( FAILED( ToggleFullscreen() ) )
  611.                         DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  612.                     Pause( false );                        
  613.                     return 0;
  614.  
  615.                 case IDM_EXIT:
  616.                     // Recieved key/menu command to exit app
  617.                     SendMessage( hWnd, WM_CLOSE, 0, 0 );
  618.                     return 0;
  619.             }
  620.             break;
  621.  
  622.         case WM_CLOSE:
  623.             Cleanup3DEnvironment();
  624.             SAFE_RELEASE( m_pD3D );
  625.             FinalCleanup();
  626.             HMENU hMenu;
  627.             hMenu = GetMenu(hWnd);
  628.             if( hMenu != NULL )
  629.                 DestroyMenu( hMenu );
  630.             DestroyWindow( hWnd );
  631.             PostQuitMessage(0);
  632.             m_hWnd = NULL;
  633.             return 0;
  634.     }
  635.  
  636.     return DefWindowProc( hWnd, uMsg, wParam, lParam );
  637. }
  638.  
  639.  
  640.  
  641.  
  642. //-----------------------------------------------------------------------------
  643. // Name: HandlePossibleSizeChange()
  644. // Desc: Reset the device if the client area size has changed.
  645. //-----------------------------------------------------------------------------
  646. HRESULT CD3DApplication::HandlePossibleSizeChange()
  647. {
  648.     HRESULT hr = S_OK;
  649.     RECT rcClientOld;
  650.     rcClientOld = m_rcWindowClient;
  651.  
  652.     if( m_bIgnoreSizeChange )
  653.         return S_OK;
  654.  
  655.     // Update window properties
  656.     GetWindowRect( m_hWnd, &m_rcWindowBounds );
  657.     GetClientRect( m_hWnd, &m_rcWindowClient );
  658.  
  659.     if( rcClientOld.right - rcClientOld.left !=
  660.         m_rcWindowClient.right - m_rcWindowClient.left ||
  661.         rcClientOld.bottom - rcClientOld.top !=
  662.         m_rcWindowClient.bottom - m_rcWindowClient.top)
  663.     {
  664.         // A new window size will require a new backbuffer
  665.         // size, so the 3D structures must be changed accordingly.
  666.         Pause( true );
  667.  
  668.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  669.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  670.     
  671.         if( m_pd3dDevice != NULL )
  672.         {
  673.             // Reset the 3D environment
  674.             if( FAILED( hr = Reset3DEnvironment() ) )
  675.             {
  676.                 if( hr != D3DERR_OUTOFVIDEOMEMORY )
  677.                     hr = D3DAPPERR_RESETFAILED;
  678.                 DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  679.             }
  680.         }
  681.         Pause( false );
  682.     }
  683.     return hr;
  684. }
  685.  
  686.  
  687.  
  688.  
  689. //-----------------------------------------------------------------------------
  690. // Name: Initialize3DEnvironment()
  691. // Desc:
  692. //-----------------------------------------------------------------------------
  693. HRESULT CD3DApplication::Initialize3DEnvironment()
  694. {
  695.     HRESULT hr;
  696.  
  697.     D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
  698.     D3DDeviceInfo* pDeviceInfo = m_d3dSettings.PDeviceInfo();
  699.  
  700.     m_bWindowed = m_d3dSettings.IsWindowed;
  701.  
  702.     // Prepare window for possible windowed/fullscreen change
  703.     AdjustWindowForChange();
  704.  
  705.     // Set up the presentation parameters
  706.     BuildPresentParamsFromSettings();
  707.  
  708.     if( pDeviceInfo->Caps.PrimitiveMiscCaps & D3DPMISCCAPS_NULLREFERENCE )
  709.     {
  710.         // Warn user about null ref device that can't render anything
  711.         DisplayErrorMsg( D3DAPPERR_NULLREFDEVICE, 0 );
  712.     }
  713.  
  714.     DWORD behaviorFlags;
  715.     if (m_d3dSettings.GetVertexProcessingType() == SOFTWARE_VP)
  716.         behaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  717.     else if (m_d3dSettings.GetVertexProcessingType() == MIXED_VP)
  718.         behaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
  719.     else if (m_d3dSettings.GetVertexProcessingType() == HARDWARE_VP)
  720.         behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  721.     else if (m_d3dSettings.GetVertexProcessingType() == PURE_HARDWARE_VP)
  722.         behaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE;
  723.     else
  724.         behaviorFlags = 0; // TODO: throw exception
  725.  
  726.     // Create the device
  727.     hr = m_pD3D->CreateDevice( m_d3dSettings.AdapterOrdinal(), pDeviceInfo->DevType,
  728.                                m_hWndFocus, behaviorFlags, &m_d3dpp,
  729.                                &m_pd3dDevice );
  730.  
  731.     if( SUCCEEDED(hr) )
  732.     {
  733.         // When moving from fullscreen to windowed mode, it is important to
  734.         // adjust the window size after recreating the device rather than
  735.         // beforehand to ensure that you get the window size you want.  For
  736.         // example, when switching from 640x480 fullscreen to windowed with
  737.         // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  738.         // the window size to 1000x600 until after the display mode has
  739.         // changed to 1024x768, because windows cannot be larger than the
  740.         // desktop.
  741.         if( m_bWindowed )
  742.         {
  743.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  744.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  745.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  746.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  747.                           SWP_SHOWWINDOW );
  748.         }
  749.  
  750.         // Store device Caps
  751.         m_pd3dDevice->GetDeviceCaps( &m_d3dCaps );
  752.         m_dwCreateFlags = behaviorFlags;
  753.  
  754.         // Store device description
  755.         if( pDeviceInfo->DevType == D3DDEVTYPE_REF )
  756.             lstrcpy( m_strDeviceStats, TEXT("REF") );
  757.         else if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  758.             lstrcpy( m_strDeviceStats, TEXT("HAL") );
  759.         else if( pDeviceInfo->DevType == D3DDEVTYPE_SW )
  760.             lstrcpy( m_strDeviceStats, TEXT("SW") );
  761.  
  762.         if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  763.             behaviorFlags & D3DCREATE_PUREDEVICE )
  764.         {
  765.             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  766.                 lstrcat( m_strDeviceStats, TEXT(" (pure hw vp)") );
  767.             else
  768.                 lstrcat( m_strDeviceStats, TEXT(" (simulated pure hw vp)") );
  769.         }
  770.         else if( behaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  771.         {
  772.             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  773.                 lstrcat( m_strDeviceStats, TEXT(" (hw vp)") );
  774.             else
  775.                 lstrcat( m_strDeviceStats, TEXT(" (simulated hw vp)") );
  776.         }
  777.         else if( behaviorFlags & D3DCREATE_MIXED_VERTEXPROCESSING )
  778.         {
  779.             if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  780.                 lstrcat( m_strDeviceStats, TEXT(" (mixed vp)") );
  781.             else
  782.                 lstrcat( m_strDeviceStats, TEXT(" (simulated mixed vp)") );
  783.         }
  784.         else if( behaviorFlags & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  785.         {
  786.             lstrcat( m_strDeviceStats, TEXT(" (sw vp)") );
  787.         }
  788.  
  789.         if( pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  790.         {
  791.             // Be sure not to overflow m_strDeviceStats when appending the adapter 
  792.             // description, since it can be long.  Note that the adapter description
  793.             // is initially CHAR and must be converted to TCHAR.
  794.             lstrcat( m_strDeviceStats, TEXT(": ") );
  795.             const int cchDesc = sizeof(pAdapterInfo->AdapterIdentifier.Description);
  796.             TCHAR szDescription[cchDesc];
  797.             DXUtil_ConvertAnsiStringToGenericCch( szDescription, 
  798.                 pAdapterInfo->AdapterIdentifier.Description, cchDesc );
  799.             int maxAppend = sizeof(m_strDeviceStats) / sizeof(TCHAR) -
  800.                 lstrlen( m_strDeviceStats ) - 1;
  801.             _tcsncat( m_strDeviceStats, szDescription, maxAppend );
  802.         }
  803.  
  804.         // Store render target surface desc
  805.         LPDIRECT3DSURFACE9 pBackBuffer = NULL;
  806.         m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  807.         pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  808.         pBackBuffer->Release();
  809.  
  810.         // Set up the fullscreen cursor
  811.         if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  812.         {
  813.             HCURSOR hCursor;
  814. #ifdef _WIN64
  815.             hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  816. #else
  817.             hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
  818. #endif
  819.             D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
  820.             m_pd3dDevice->ShowCursor( true );
  821.         }
  822.  
  823.         // Confine cursor to fullscreen window
  824.         if( m_bClipCursorWhenFullscreen )
  825.         {
  826.             if (!m_bWindowed )
  827.             {
  828.                 RECT rcWindow;
  829.                 GetWindowRect( m_hWnd, &rcWindow );
  830.                 ClipCursor( &rcWindow );
  831.             }
  832.             else
  833.             {
  834.                 ClipCursor( NULL );
  835.             }
  836.         }
  837.  
  838.         // Initialize the app's device-dependent objects
  839.         hr = InitDeviceObjects();
  840.         if( FAILED(hr) )
  841.         {
  842.             DeleteDeviceObjects();
  843.         }
  844.         else
  845.         {
  846.             m_bDeviceObjectsInited = true;
  847.             hr = RestoreDeviceObjects();
  848.             if( FAILED(hr) )
  849.             {
  850.                 InvalidateDeviceObjects();
  851.             }
  852.             else
  853.             {
  854.                 m_bDeviceObjectsRestored = true;
  855.                 return S_OK;
  856.             }
  857.         }
  858.  
  859.         // Cleanup before we try again
  860.         Cleanup3DEnvironment();
  861.     }
  862.  
  863.     // If that failed, fall back to the reference rasterizer
  864.     if( hr != D3DAPPERR_MEDIANOTFOUND && 
  865.         hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) && 
  866.         pDeviceInfo->DevType == D3DDEVTYPE_HAL )
  867.     {
  868.         if (FindBestWindowedMode(false, true))
  869.         {
  870.             m_bWindowed = true;
  871.             AdjustWindowForChange();
  872.             // Make sure main window isn't topmost, so error message is visible
  873.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  874.                           m_rcWindowBounds.left, m_rcWindowBounds.top,
  875.                           ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  876.                           ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  877.                           SWP_SHOWWINDOW );
  878.  
  879.             // Let the user know we are switching from HAL to the reference rasterizer
  880.             DisplayErrorMsg( hr, MSGWARN_SWITCHEDTOREF );
  881.  
  882.             hr = Initialize3DEnvironment();
  883.         }
  884.     }
  885.     return hr;
  886. }
  887.  
  888.  
  889.  
  890.  
  891. //-----------------------------------------------------------------------------
  892. // Name: BuildPresentParamsFromSettings()
  893. // Desc:
  894. //-----------------------------------------------------------------------------
  895. void CD3DApplication::BuildPresentParamsFromSettings()
  896. {
  897.     m_d3dpp.Windowed               = m_d3dSettings.IsWindowed;
  898.     m_d3dpp.BackBufferCount        = 1;
  899.     m_d3dpp.MultiSampleType        = m_d3dSettings.MultisampleType();
  900.     m_d3dpp.MultiSampleQuality     = m_d3dSettings.MultisampleQuality();
  901.     m_d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
  902.     m_d3dpp.EnableAutoDepthStencil = m_d3dEnumeration.AppUsesDepthBuffer;
  903.     m_d3dpp.hDeviceWindow          = m_hWnd;
  904.     if( m_d3dEnumeration.AppUsesDepthBuffer )
  905.     {
  906.         m_d3dpp.Flags              = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
  907.         m_d3dpp.AutoDepthStencilFormat = m_d3dSettings.DepthStencilBufferFormat();
  908.     }
  909.     else
  910.     {
  911.         m_d3dpp.Flags              = 0;
  912.     }
  913.  
  914.     if( m_bWindowed )
  915.     {
  916.         m_d3dpp.BackBufferWidth  = m_rcWindowClient.right - m_rcWindowClient.left;
  917.         m_d3dpp.BackBufferHeight = m_rcWindowClient.bottom - m_rcWindowClient.top;
  918.         m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
  919.         m_d3dpp.FullScreen_RefreshRateInHz = 0;
  920.         m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
  921.     }
  922.     else
  923.     {
  924.         m_d3dpp.BackBufferWidth  = m_d3dSettings.DisplayMode().Width;
  925.         m_d3dpp.BackBufferHeight = m_d3dSettings.DisplayMode().Height;
  926.         m_d3dpp.BackBufferFormat = m_d3dSettings.PDeviceCombo()->BackBufferFormat;
  927.         m_d3dpp.FullScreen_RefreshRateInHz = m_d3dSettings.Fullscreen_DisplayMode.RefreshRate;
  928.         m_d3dpp.PresentationInterval = m_d3dSettings.PresentInterval();
  929.     }
  930. }
  931.  
  932.  
  933.  
  934.  
  935. //-----------------------------------------------------------------------------
  936. // Name: Reset3DEnvironment()
  937. // Desc:
  938. //-----------------------------------------------------------------------------
  939. HRESULT CD3DApplication::Reset3DEnvironment()
  940. {
  941.     HRESULT hr;
  942.  
  943.     // Release all vidmem objects
  944.     if( m_bDeviceObjectsRestored )
  945.     {
  946.         m_bDeviceObjectsRestored = false;
  947.         InvalidateDeviceObjects();
  948.     }
  949.     // Reset the device
  950.     if( FAILED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
  951.         return hr;
  952.  
  953.     // Store render target surface desc
  954.     LPDIRECT3DSURFACE9 pBackBuffer;
  955.     m_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  956.     pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  957.     pBackBuffer->Release();
  958.  
  959.     // Set up the fullscreen cursor
  960.     if( m_bShowCursorWhenFullscreen && !m_bWindowed )
  961.     {
  962.         HCURSOR hCursor;
  963. #ifdef _WIN64
  964.         hCursor = (HCURSOR)GetClassLongPtr( m_hWnd, GCLP_HCURSOR );
  965. #else
  966.         hCursor = (HCURSOR)ULongToHandle( GetClassLong( m_hWnd, GCL_HCURSOR ) );
  967. #endif
  968.         D3DUtil_SetDeviceCursor( m_pd3dDevice, hCursor, true );
  969.         m_pd3dDevice->ShowCursor( true );
  970.     }
  971.  
  972.     // Confine cursor to fullscreen window
  973.     if( m_bClipCursorWhenFullscreen )
  974.     {
  975.         if (!m_bWindowed )
  976.         {
  977.             RECT rcWindow;
  978.             GetWindowRect( m_hWnd, &rcWindow );
  979.             ClipCursor( &rcWindow );
  980.         }
  981.         else
  982.         {
  983.             ClipCursor( NULL );
  984.         }
  985.     }
  986.  
  987.     // Initialize the app's device-dependent objects
  988.     hr = RestoreDeviceObjects();
  989.     if( FAILED(hr) )
  990.     {
  991.         InvalidateDeviceObjects();
  992.         return hr;
  993.     }
  994.     m_bDeviceObjectsRestored = true;
  995.  
  996.     // If the app is paused, trigger the rendering of the current frame
  997.     if( false == m_bFrameMoving )
  998.     {
  999.         m_bSingleStep = true;
  1000.         DXUtil_Timer( TIMER_START );
  1001.         DXUtil_Timer( TIMER_STOP );
  1002.     }
  1003.  
  1004.     return S_OK;
  1005. }
  1006.  
  1007.  
  1008.  
  1009.  
  1010. //-----------------------------------------------------------------------------
  1011. // Name: ToggleFullScreen()
  1012. // Desc: Called when user toggles between fullscreen mode and windowed mode
  1013. //-----------------------------------------------------------------------------
  1014. HRESULT CD3DApplication::ToggleFullscreen()
  1015. {
  1016.     HRESULT hr;
  1017.     int AdapterOrdinalOld = m_d3dSettings.AdapterOrdinal();
  1018.     D3DDEVTYPE DevTypeOld = m_d3dSettings.DevType();
  1019.  
  1020.     Pause( true );
  1021.     m_bIgnoreSizeChange = true;
  1022.  
  1023.     // Toggle the windowed state
  1024.     m_bWindowed = !m_bWindowed;
  1025.     m_d3dSettings.IsWindowed = m_bWindowed;
  1026.  
  1027.     // Prepare window for windowed/fullscreen change
  1028.     AdjustWindowForChange();
  1029.  
  1030.     // If AdapterOrdinal and DevType are the same, we can just do a Reset().
  1031.     // If they've changed, we need to do a complete device teardown/rebuild.
  1032.     if (m_d3dSettings.AdapterOrdinal() == AdapterOrdinalOld &&
  1033.         m_d3dSettings.DevType() == DevTypeOld)
  1034.     {
  1035.         // Reset the 3D device
  1036.         BuildPresentParamsFromSettings();
  1037.         hr = Reset3DEnvironment();
  1038.     }
  1039.     else
  1040.     {
  1041.         Cleanup3DEnvironment();
  1042.         hr = Initialize3DEnvironment();
  1043.     }
  1044.     if( FAILED( hr ) )
  1045.     {
  1046.         if( hr != D3DERR_OUTOFVIDEOMEMORY )
  1047.             hr = D3DAPPERR_RESETFAILED;
  1048.         m_bIgnoreSizeChange = false;
  1049.         if( !m_bWindowed )
  1050.         {
  1051.             // Restore window type to windowed mode
  1052.             m_bWindowed = !m_bWindowed;
  1053.             m_d3dSettings.IsWindowed = m_bWindowed;
  1054.             AdjustWindowForChange();
  1055.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1056.                         m_rcWindowBounds.left, m_rcWindowBounds.top,
  1057.                         ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1058.                         ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1059.                         SWP_SHOWWINDOW );
  1060.         }
  1061.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1062.     }
  1063.  
  1064.     m_bIgnoreSizeChange = false;
  1065.  
  1066.     // When moving from fullscreen to windowed mode, it is important to
  1067.     // adjust the window size after resetting the device rather than
  1068.     // beforehand to ensure that you get the window size you want.  For
  1069.     // example, when switching from 640x480 fullscreen to windowed with
  1070.     // a 1000x600 window on a 1024x768 desktop, it is impossible to set
  1071.     // the window size to 1000x600 until after the display mode has
  1072.     // changed to 1024x768, because windows cannot be larger than the
  1073.     // desktop.
  1074.     if( m_bWindowed )
  1075.     {
  1076.         SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1077.                       m_rcWindowBounds.left, m_rcWindowBounds.top,
  1078.                       ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1079.                       ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1080.                       SWP_SHOWWINDOW );
  1081.     }
  1082.  
  1083.     Pause( false );
  1084.     return S_OK;
  1085. }
  1086.  
  1087.  
  1088.  
  1089.  
  1090. //-----------------------------------------------------------------------------
  1091. // Name: ForceWindowed()
  1092. // Desc: Switch to a windowed mode, even if that means picking a new device
  1093. //       and/or adapter
  1094. //-----------------------------------------------------------------------------
  1095. HRESULT CD3DApplication::ForceWindowed()
  1096. {
  1097.     HRESULT hr;
  1098.  
  1099.     if( m_bWindowed )
  1100.         return S_OK;
  1101.  
  1102.     if( !FindBestWindowedMode(false, false) )
  1103.     {
  1104.         return E_FAIL;
  1105.     }
  1106.     m_bWindowed = true;
  1107.  
  1108.     // Now destroy the current 3D device objects, then reinitialize
  1109.  
  1110.     Pause( true );
  1111.  
  1112.     // Release all scene objects that will be re-created for the new device
  1113.     Cleanup3DEnvironment();
  1114.  
  1115.     // Create the new device
  1116.     if( FAILED(hr = Initialize3DEnvironment() ) )
  1117.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1118.  
  1119.     Pause( false );
  1120.     return S_OK;
  1121. }
  1122.  
  1123.  
  1124.  
  1125.  
  1126. //-----------------------------------------------------------------------------
  1127. // Name: AdjustWindowForChange()
  1128. // Desc: Prepare the window for a possible change between windowed mode and
  1129. //       fullscreen mode.  This function is virtual and thus can be overridden
  1130. //       to provide different behavior, such as switching to an entirely
  1131. //       different window for fullscreen mode (as in the MFC sample apps).
  1132. //-----------------------------------------------------------------------------
  1133. HRESULT CD3DApplication::AdjustWindowForChange()
  1134. {
  1135.     if( m_bWindowed )
  1136.     {
  1137.         // Set windowed-mode style
  1138.         SetWindowLong( m_hWnd, GWL_STYLE, m_dwWindowStyle );
  1139.         if( m_hMenu != NULL )
  1140.         {
  1141.             SetMenu( m_hWnd, m_hMenu );
  1142.             m_hMenu = NULL;
  1143.         }
  1144.     }
  1145.     else
  1146.     {
  1147.         // Set fullscreen-mode style
  1148.         SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
  1149.         if( m_hMenu == NULL )
  1150.         {
  1151.             m_hMenu = GetMenu( m_hWnd );
  1152.             SetMenu( m_hWnd, NULL );
  1153.         }
  1154.     }
  1155.     return S_OK;
  1156. }
  1157.  
  1158.  
  1159.  
  1160.  
  1161. //-----------------------------------------------------------------------------
  1162. // Name: UserSelectNewDevice()
  1163. // Desc: Displays a dialog so the user can select a new adapter, device, or
  1164. //       display mode, and then recreates the 3D environment if needed
  1165. //-----------------------------------------------------------------------------
  1166. HRESULT CD3DApplication::UserSelectNewDevice()
  1167. {
  1168.     HRESULT hr;
  1169.  
  1170.     // Can't display dialogs in fullscreen mode
  1171.     if( m_bWindowed == false )
  1172.     {
  1173.         if( FAILED( ToggleFullscreen() ) )
  1174.         {
  1175.             DisplayErrorMsg( D3DAPPERR_RESETFAILED, MSGERR_APPMUSTEXIT );
  1176.             return E_FAIL;
  1177.         }
  1178.     }
  1179.  
  1180.     CD3DSettingsDialog settingsDialog( &m_d3dEnumeration, &m_d3dSettings);
  1181.     if( settingsDialog.ShowDialog( m_hWnd ) != IDOK )
  1182.         return S_OK;
  1183.     settingsDialog.GetFinalSettings( &m_d3dSettings );
  1184.  
  1185.     m_bWindowed = m_d3dSettings.IsWindowed;
  1186.  
  1187.     // Release all scene objects that will be re-created for the new device
  1188.     Cleanup3DEnvironment();
  1189.  
  1190.     // Inform the display class of the change. It will internally
  1191.     // re-create valid surfaces, a d3ddevice, etc.
  1192.     if( FAILED( hr = Initialize3DEnvironment() ) )
  1193.     {
  1194.         if( hr != D3DERR_OUTOFVIDEOMEMORY )
  1195.             hr = D3DAPPERR_RESETFAILED;
  1196.         if( !m_bWindowed )
  1197.         {
  1198.             // Restore window type to windowed mode
  1199.             m_bWindowed = !m_bWindowed;
  1200.             m_d3dSettings.IsWindowed = m_bWindowed;
  1201.             AdjustWindowForChange();
  1202.             SetWindowPos( m_hWnd, HWND_NOTOPMOST,
  1203.                         m_rcWindowBounds.left, m_rcWindowBounds.top,
  1204.                         ( m_rcWindowBounds.right - m_rcWindowBounds.left ),
  1205.                         ( m_rcWindowBounds.bottom - m_rcWindowBounds.top ),
  1206.                         SWP_SHOWWINDOW );
  1207.         }
  1208.         return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  1209.     }
  1210.  
  1211.     // If the app is paused, trigger the rendering of the current frame
  1212.     if( false == m_bFrameMoving )
  1213.     {
  1214.         m_bSingleStep = true;
  1215.         DXUtil_Timer( TIMER_START );
  1216.         DXUtil_Timer( TIMER_STOP );
  1217.     }
  1218.     return S_OK;
  1219. }
  1220.  
  1221.  
  1222.  
  1223.  
  1224. //-----------------------------------------------------------------------------
  1225. // Name: Run()
  1226. // Desc:
  1227. //-----------------------------------------------------------------------------
  1228. INT CD3DApplication::Run()
  1229. {
  1230.     // Load keyboard accelerators
  1231.     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  1232.  
  1233.     // Now we're ready to recieve and process Windows messages.
  1234.     bool bGotMsg;
  1235.     MSG  msg;
  1236.     msg.message = WM_NULL;
  1237.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  1238.  
  1239.     while( WM_QUIT != msg.message  )
  1240.     {
  1241.         // Use PeekMessage() if the app is active, so we can use idle time to
  1242.         // render the scene. Else, use GetMessage() to avoid eating CPU time.
  1243.         if( m_bActive )
  1244.             bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 );
  1245.         else
  1246.             bGotMsg = ( GetMessage( &msg, NULL, 0U, 0U ) != 0 );
  1247.  
  1248.         if( bGotMsg )
  1249.         {
  1250.             // Translate and dispatch the message
  1251.             if( hAccel == NULL || m_hWnd == NULL || 
  1252.                 0 == TranslateAccelerator( m_hWnd, hAccel, &msg ) )
  1253.             {
  1254.                 TranslateMessage( &msg );
  1255.                 DispatchMessage( &msg );
  1256.             }
  1257.         }
  1258.         else
  1259.         {
  1260.             if( m_bDeviceLost )
  1261.             {
  1262.                 // Yield some CPU time to other processes
  1263.                 Sleep( 100 ); // 100 milliseconds
  1264.             }
  1265.             // Render a frame during idle time (no messages are waiting)
  1266.             if( m_bActive )
  1267.             {
  1268.                 if( FAILED( Render3DEnvironment() ) )
  1269.                     SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  1270.             }
  1271.         }
  1272.     }
  1273.     if( hAccel != NULL )
  1274.         DestroyAcceleratorTable( hAccel );
  1275.  
  1276.     return (INT)msg.wParam;
  1277. }
  1278.  
  1279.  
  1280.  
  1281.  
  1282. //-----------------------------------------------------------------------------
  1283. // Name: Render3DEnvironment()
  1284. // Desc: Draws the scene.
  1285. //-----------------------------------------------------------------------------
  1286. HRESULT CD3DApplication::Render3DEnvironment()
  1287. {
  1288.     HRESULT hr;
  1289.  
  1290.     if( m_bDeviceLost )
  1291.     {
  1292.         // Test the cooperative level to see if it's okay to render
  1293.         if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  1294.         {
  1295.             // If the device was lost, do not render until we get it back
  1296.             if( D3DERR_DEVICELOST == hr )
  1297.                 return S_OK;
  1298.  
  1299.             // Check if the device needs to be reset.
  1300.             if( D3DERR_DEVICENOTRESET == hr )
  1301.             {
  1302.                 // If we are windowed, read the desktop mode and use the same format for
  1303.                 // the back buffer
  1304.                 if( m_bWindowed )
  1305.                 {
  1306.                     D3DAdapterInfo* pAdapterInfo = m_d3dSettings.PAdapterInfo();
  1307.                     m_pD3D->GetAdapterDisplayMode( pAdapterInfo->AdapterOrdinal, &m_d3dSettings.Windowed_DisplayMode );
  1308.                     m_d3dpp.BackBufferFormat = m_d3dSettings.Windowed_DisplayMode.Format;
  1309.                 }
  1310.  
  1311.                 if( FAILED( hr = Reset3DEnvironment() ) )
  1312.                     return hr;
  1313.             }
  1314.             return hr;
  1315.         }
  1316.         m_bDeviceLost = false;
  1317.     }
  1318.  
  1319.     // Get the app's time, in seconds. Skip rendering if no time elapsed
  1320.     FLOAT fAppTime        = DXUtil_Timer( TIMER_GETAPPTIME );
  1321.     FLOAT fElapsedAppTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  1322.     if( ( 0.0f == fElapsedAppTime ) && m_bFrameMoving )
  1323.         return S_OK;
  1324.  
  1325.     // FrameMove (animate) the scene
  1326.     if( m_bFrameMoving || m_bSingleStep )
  1327.     {
  1328.         // Store the time for the app
  1329.         m_fTime        = fAppTime;
  1330.         m_fElapsedTime = fElapsedAppTime;
  1331.  
  1332.         // Frame move the scene
  1333.         if( FAILED( hr = FrameMove() ) )
  1334.             return hr;
  1335.  
  1336.         m_bSingleStep = false;
  1337.     }
  1338.  
  1339.     // Render the scene as normal
  1340.     if( FAILED( hr = Render() ) )
  1341.         return hr;
  1342.  
  1343.     UpdateStats();
  1344.  
  1345.     // Show the frame on the primary surface.
  1346.     hr = m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  1347.     if( D3DERR_DEVICELOST == hr )
  1348.         m_bDeviceLost = true;
  1349.  
  1350.     return S_OK;
  1351. }
  1352.  
  1353.  
  1354.  
  1355.  
  1356. //-----------------------------------------------------------------------------
  1357. // Name: UpdateStats()
  1358. // Desc: 
  1359. //-----------------------------------------------------------------------------
  1360. void CD3DApplication::UpdateStats()
  1361. {
  1362.     // Keep track of the frame count
  1363.     static FLOAT fLastTime = 0.0f;
  1364.     static DWORD dwFrames  = 0;
  1365.     FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  1366.     ++dwFrames;
  1367.  
  1368.     // Update the scene stats once per second
  1369.     if( fTime - fLastTime > 1.0f )
  1370.     {
  1371.         m_fFPS    = dwFrames / (fTime - fLastTime);
  1372.         fLastTime = fTime;
  1373.         dwFrames  = 0;
  1374.  
  1375.         TCHAR strFmt[100];
  1376.         D3DFORMAT fmtAdapter = m_d3dSettings.DisplayMode().Format;
  1377.         if( fmtAdapter == m_d3dsdBackBuffer.Format )
  1378.         {
  1379.             lstrcpyn( strFmt, D3DUtil_D3DFormatToString( fmtAdapter, false ), 100 );
  1380.         }
  1381.         else
  1382.         {
  1383.             _sntprintf( strFmt, 100, TEXT("backbuf %s, adapter %s"), 
  1384.                 D3DUtil_D3DFormatToString( m_d3dsdBackBuffer.Format, false ), 
  1385.                 D3DUtil_D3DFormatToString( fmtAdapter, false ) );
  1386.         }
  1387.         strFmt[99] = TEXT('\0');
  1388.  
  1389.         TCHAR strDepthFmt[100];
  1390.         if( m_d3dEnumeration.AppUsesDepthBuffer )
  1391.         {
  1392.             _sntprintf( strDepthFmt, 100, TEXT(" (%s)"), 
  1393.                 D3DUtil_D3DFormatToString( m_d3dSettings.DepthStencilBufferFormat(), false ) );
  1394.             strDepthFmt[99] = TEXT('\0');
  1395.         }
  1396.         else
  1397.         {
  1398.             // No depth buffer
  1399.             strDepthFmt[0] = TEXT('\0');
  1400.         }
  1401.  
  1402.         TCHAR* pstrMultiSample;
  1403.         switch( m_d3dSettings.MultisampleType() )
  1404.         {
  1405.         case D3DMULTISAMPLE_NONMASKABLE:  pstrMultiSample = TEXT(" (Nonmaskable Multisample)"); break;
  1406.         case D3DMULTISAMPLE_2_SAMPLES:  pstrMultiSample = TEXT(" (2x Multisample)"); break;
  1407.         case D3DMULTISAMPLE_3_SAMPLES:  pstrMultiSample = TEXT(" (3x Multisample)"); break;
  1408.         case D3DMULTISAMPLE_4_SAMPLES:  pstrMultiSample = TEXT(" (4x Multisample)"); break;
  1409.         case D3DMULTISAMPLE_5_SAMPLES:  pstrMultiSample = TEXT(" (5x Multisample)"); break;
  1410.         case D3DMULTISAMPLE_6_SAMPLES:  pstrMultiSample = TEXT(" (6x Multisample)"); break;
  1411.         case D3DMULTISAMPLE_7_SAMPLES:  pstrMultiSample = TEXT(" (7x Multisample)"); break;
  1412.         case D3DMULTISAMPLE_8_SAMPLES:  pstrMultiSample = TEXT(" (8x Multisample)"); break;
  1413.         case D3DMULTISAMPLE_9_SAMPLES:  pstrMultiSample = TEXT(" (9x Multisample)"); break;
  1414.         case D3DMULTISAMPLE_10_SAMPLES: pstrMultiSample = TEXT(" (10x Multisample)"); break;
  1415.         case D3DMULTISAMPLE_11_SAMPLES: pstrMultiSample = TEXT(" (11x Multisample)"); break;
  1416.         case D3DMULTISAMPLE_12_SAMPLES: pstrMultiSample = TEXT(" (12x Multisample)"); break;
  1417.         case D3DMULTISAMPLE_13_SAMPLES: pstrMultiSample = TEXT(" (13x Multisample)"); break;
  1418.         case D3DMULTISAMPLE_14_SAMPLES: pstrMultiSample = TEXT(" (14x Multisample)"); break;
  1419.         case D3DMULTISAMPLE_15_SAMPLES: pstrMultiSample = TEXT(" (15x Multisample)"); break;
  1420.         case D3DMULTISAMPLE_16_SAMPLES: pstrMultiSample = TEXT(" (16x Multisample)"); break;
  1421.         default:                        pstrMultiSample = TEXT(""); break;
  1422.         }
  1423.  
  1424.         const int cchMaxFrameStats = sizeof(m_strFrameStats) / sizeof(TCHAR);
  1425.         _sntprintf( m_strFrameStats, cchMaxFrameStats, _T("%.02f fps (%dx%d), %s%s%s"), m_fFPS,
  1426.                     m_d3dsdBackBuffer.Width, m_d3dsdBackBuffer.Height,
  1427.                     strFmt, strDepthFmt, pstrMultiSample );
  1428.         m_strFrameStats[cchMaxFrameStats - 1] = TEXT('\0');
  1429.     }
  1430. }
  1431.  
  1432.  
  1433.  
  1434.  
  1435. //-----------------------------------------------------------------------------
  1436. // Name: Pause()
  1437. // Desc: Called in to toggle the pause state of the app.
  1438. //-----------------------------------------------------------------------------
  1439. void CD3DApplication::Pause( bool bPause )
  1440. {
  1441.     static DWORD dwAppPausedCount = 0;
  1442.  
  1443.     dwAppPausedCount += ( bPause ? +1 : -1 );
  1444.     m_bActive         = ( dwAppPausedCount ? false : true );
  1445.  
  1446.     // Handle the first pause request (of many, nestable pause requests)
  1447.     if( bPause && ( 1 == dwAppPausedCount ) )
  1448.     {
  1449.         // Stop the scene from animating
  1450.         if( m_bFrameMoving )
  1451.             DXUtil_Timer( TIMER_STOP );
  1452.     }
  1453.  
  1454.     if( 0 == dwAppPausedCount )
  1455.     {
  1456.         // Restart the timers
  1457.         if( m_bFrameMoving )
  1458.             DXUtil_Timer( TIMER_START );
  1459.     }
  1460. }
  1461.  
  1462.  
  1463.  
  1464.  
  1465. //-----------------------------------------------------------------------------
  1466. // Name: Cleanup3DEnvironment()
  1467. // Desc: Cleanup scene objects
  1468. //-----------------------------------------------------------------------------
  1469. void CD3DApplication::Cleanup3DEnvironment()
  1470. {
  1471.     if( m_pd3dDevice != NULL )
  1472.     {
  1473.         if( m_bDeviceObjectsRestored )
  1474.         {
  1475.             m_bDeviceObjectsRestored = false;
  1476.             InvalidateDeviceObjects();
  1477.         }
  1478.         if( m_bDeviceObjectsInited )
  1479.         {
  1480.             m_bDeviceObjectsInited = false;
  1481.             DeleteDeviceObjects();
  1482.         }
  1483.  
  1484.         if( m_pd3dDevice->Release() > 0 )
  1485.             DisplayErrorMsg( D3DAPPERR_NONZEROREFCOUNT, MSGERR_APPMUSTEXIT );
  1486.         m_pd3dDevice = NULL;
  1487.     }
  1488. }
  1489.  
  1490.  
  1491.  
  1492.  
  1493. //-----------------------------------------------------------------------------
  1494. // Name: DisplayErrorMsg()
  1495. // Desc: Displays error messages in a message box
  1496. //-----------------------------------------------------------------------------
  1497. HRESULT CD3DApplication::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  1498. {
  1499.     static bool s_bFatalErrorReported = false;
  1500.     TCHAR strMsg[512];
  1501.  
  1502.     // If a fatal error message has already been reported, the app
  1503.     // is already shutting down, so don't show more error messages.
  1504.     if( s_bFatalErrorReported )
  1505.         return hr;
  1506.  
  1507.     switch( hr )
  1508.     {
  1509.         case D3DAPPERR_NODIRECT3D:
  1510.             _tcscpy( strMsg, _T("Could not initialize Direct3D. You may\n")
  1511.                              _T("want to check that the latest version of\n")
  1512.                              _T("DirectX is correctly installed on your\n")
  1513.                              _T("system.  Also make sure that this program\n")
  1514.                              _T("was compiled with header files that match\n")
  1515.                              _T("the installed DirectX DLLs.") );
  1516.             break;
  1517.  
  1518.         case D3DAPPERR_NOCOMPATIBLEDEVICES:
  1519.             _tcscpy( strMsg, _T("Could not find any compatible Direct3D\n")
  1520.                              _T("devices.") );
  1521.             break;
  1522.  
  1523.         case D3DAPPERR_NOWINDOWABLEDEVICES:
  1524.             _tcscpy( strMsg, _T("This sample cannot run in a desktop\n")
  1525.                              _T("window with the current display settings.\n")
  1526.                              _T("Please change your desktop settings to a\n")
  1527.                              _T("16- or 32-bit display mode and re-run this\n")
  1528.                              _T("sample.") );
  1529.             break;
  1530.  
  1531.         case D3DAPPERR_NOHARDWAREDEVICE:
  1532.             _tcscpy( strMsg, _T("No hardware-accelerated Direct3D devices\n")
  1533.                              _T("were found.") );
  1534.             break;
  1535.  
  1536.         case D3DAPPERR_HALNOTCOMPATIBLE:
  1537.             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
  1538.                              _T("not available on your Direct3D hardware\n")
  1539.                              _T("accelerator.") );
  1540.             break;
  1541.  
  1542.         case D3DAPPERR_NOWINDOWEDHAL:
  1543.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
  1544.                              _T("render into a window.\n")
  1545.                              _T("Press F2 while the app is running to see a\n")
  1546.                              _T("list of available devices and modes.") );
  1547.             break;
  1548.  
  1549.         case D3DAPPERR_NODESKTOPHAL:
  1550.             _tcscpy( strMsg, _T("Your Direct3D hardware accelerator cannot\n")
  1551.                              _T("render into a window with the current\n")
  1552.                              _T("desktop display settings.\n")
  1553.                              _T("Press F2 while the app is running to see a\n")
  1554.                              _T("list of available devices and modes.") );
  1555.             break;
  1556.  
  1557.         case D3DAPPERR_NOHALTHISMODE:
  1558.             _tcscpy( strMsg, _T("This sample requires functionality that is\n")
  1559.                              _T("not available on your Direct3D hardware\n")
  1560.                              _T("accelerator with the current desktop display\n")
  1561.                              _T("settings.\n")
  1562.                              _T("Press F2 while the app is running to see a\n")
  1563.                              _T("list of available devices and modes.") );
  1564.             break;
  1565.  
  1566.         case D3DAPPERR_MEDIANOTFOUND:
  1567.         case HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):
  1568.             _tcscpy( strMsg, _T("Could not load required media." ) );
  1569.             break;
  1570.  
  1571.         case D3DAPPERR_RESETFAILED:
  1572.             _tcscpy( strMsg, _T("Could not reset the Direct3D device." ) );
  1573.             break;
  1574.  
  1575.         case D3DAPPERR_NONZEROREFCOUNT:
  1576.             _tcscpy( strMsg, _T("A D3D object has a non-zero reference\n")
  1577.                              _T("count (meaning things were not properly\n")
  1578.                              _T("cleaned up).") );
  1579.             break;
  1580.  
  1581.         case D3DAPPERR_NULLREFDEVICE:
  1582.             _tcscpy( strMsg, _T("Warning: Nothing will be rendered.\n")
  1583.                              _T("The reference rendering device was selected, but your\n")
  1584.                              _T("computer only has a reduced-functionality reference device\n")
  1585.                              _T("installed.  Install the DirectX SDK to get the full\n")
  1586.                              _T("reference device.\n") );
  1587.             break;
  1588.  
  1589.         case E_OUTOFMEMORY:
  1590.             _tcscpy( strMsg, _T("Not enough memory.") );
  1591.             break;
  1592.  
  1593.         case D3DERR_OUTOFVIDEOMEMORY:
  1594.             _tcscpy( strMsg, _T("Not enough video memory.") );
  1595.             break;
  1596.  
  1597.         default:
  1598.             _tcscpy( strMsg, _T("Generic application error. Enable\n")
  1599.                              _T("debug output for detailed information.") );
  1600.     }
  1601.  
  1602.     if( MSGERR_APPMUSTEXIT == dwType )
  1603.     {
  1604.         s_bFatalErrorReported = true;
  1605.         _tcscat( strMsg, _T("\n\nThis sample will now exit.") );
  1606.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
  1607.  
  1608.         // Close the window, which shuts down the app
  1609.         if( m_hWnd )
  1610.             SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
  1611.     }
  1612.     else
  1613.     {
  1614.         if( MSGWARN_SWITCHEDTOREF == dwType )
  1615.             _tcscat( strMsg, _T("\n\nSwitching to the reference rasterizer,\n")
  1616.                              _T("a software device that implements the entire\n")
  1617.                              _T("Direct3D feature set, but runs very slowly.") );
  1618.         MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
  1619.     }
  1620.  
  1621.     return hr;
  1622. }
  1623.